package ru.ifmo;

/**
 * Created by Admin on 03.02.15.
 */

import sofia_kp.SIBResponse;
import sofia_kp.iKPIC_subscribeHandler2;
import sofia_kp.KPICore;

import java.util.ArrayList;
import java.util.Vector;

public class SmartSpaceKP {

    private KPICore core;
    private ArrayList<String> subscriptionIdList;
    final boolean timeDebug = false;

    public SmartSpaceKP(String host, int port, String spaceName, boolean needCleanup) throws SmartSpaceException {
        long startTime = System.currentTimeMillis();
        core = new KPICore(host, port, spaceName);
        subscriptionIdList = new ArrayList<String>();

        //core.enable_debug_message();

        SIBResponse joinResponse = core.join();

        if (joinResponse.isConfirmed())  {
            System.out.println("Joined!");

            if (needCleanup) {
                // Если необходимо очистить смартспейс от всей информации что там есть
                cleanSmartSpace();
            }

        } else {

            if (timeDebug) {
                System.out.println("SmartSpaceKP constructor: " + (System.currentTimeMillis() - startTime));
            }

            throw new SmartSpaceException(joinResponse.Message);
        }

        if (timeDebug) {
            System.out.println("SmartSpaceKP constructor: " + (System.currentTimeMillis() - startTime));
        }
    }

    public Vector<SmartSpaceTriplet> query(SmartSpaceTriplet triplet) throws SmartSpaceException {
        //Vector<Vector<String>> query = new Vector<Vector<String>>();
        //query.add(triplet.getTriplet());

        long startTime = System.currentTimeMillis();

        SIBResponse queryResponse = core.queryRDF(triplet.getSubject(), triplet.getPredicate(), triplet.getObject(), "uri", "literal");

        if (queryResponse.isConfirmed()) {
            Vector<Vector<String>> stringVectorResult = queryResponse.query_results;

            Vector<SmartSpaceTriplet> result = new Vector<SmartSpaceTriplet>();

            for (Vector<String> it : stringVectorResult) {
                result.add(new SmartSpaceTriplet(it));
            }

            if (timeDebug) {
                System.out.println("SmartSpaceKP constructor: " + (System.currentTimeMillis() - startTime));
            }

            return result;
        } else {

            if (timeDebug) {
                System.out.println("SmartSpaceKP query: " + (System.currentTimeMillis() - startTime));
            }
            throw new SmartSpaceException(queryResponse.Message);
        }


    }

    /**
     * To Delete
     * */
    @Deprecated
    private Vector<Vector<String>> reformatTripletToSIBD(SmartSpaceTriplet triplet) {
        Vector<Vector<String>> tripleList = new Vector<Vector<String>>();
        tripleList.add(triplet.getTriplet());
        return tripleList;
    }

    protected void setHandler(iKPIC_subscribeHandler2 handler) {
        core.setEventHandler2(handler);
    }

    public void insertData(SmartSpaceTriplet triplet) throws SmartSpaceException {
        long startTime = System.currentTimeMillis();
        SIBResponse insertResponse = core.insert(triplet.getSubject(), triplet.getPredicate(), triplet.getObject(), "uri", "literal");
        if (!insertResponse.isConfirmed()) {
            String text = String.format("KP failed to insert triplet: (%s, %s, %s)", triplet.getSubject(), triplet.getPredicate(), triplet.getObject());

            if (timeDebug) {
                System.out.println("SmartSpaceKP insertData: " + (System.currentTimeMillis() - startTime));
            }

            throw new SmartSpaceException(text + '\n' + insertResponse.Message);
        }
        if (timeDebug) {
            System.out.println("SmartSpaceKP insertData: " + (System.currentTimeMillis() - startTime));
        }
    }

    public void updateData(SmartSpaceTriplet newTriplet, SmartSpaceTriplet oldTriplet) throws SmartSpaceException {
        long startTime = System.currentTimeMillis();
        SIBResponse updateResponse = core.update(   newTriplet.getSubject(), newTriplet.getPredicate(), newTriplet.getObject(), "uri", "literal",
                                                    oldTriplet.getSubject(), oldTriplet.getPredicate(), oldTriplet.getObject(), "uri", "literal");

        if (!updateResponse.isConfirmed()) {
            String text = String.format("KP failed to update triplet! Old triplet: (%s %s %s), new triplet (%s %s %s)", newTriplet.getSubject(), newTriplet.getPredicate(), newTriplet.getObject(),
                                                                                                                        oldTriplet.getSubject(), oldTriplet.getPredicate(), oldTriplet.getObject());


            if (timeDebug) {
                System.out.println("SmartSpaceKP updateData: " + (System.currentTimeMillis() - startTime));
            }

            throw new SmartSpaceException(text + '\n' + updateResponse.Message);
        }

        if (timeDebug) {
            System.out.println("SmartSpaceKP updateData: " + (System.currentTimeMillis() - startTime));
        }
}

    public void removeData(SmartSpaceTriplet triplet) throws SmartSpaceException {
        long startTime = System.currentTimeMillis();
        SIBResponse removeResponse = core.remove(triplet.getSubject(), triplet.getPredicate(), triplet.getObject(), "uri", "literal");
        if (!removeResponse.isConfirmed()) {
            String text = String.format("KP failed to remove triplet: (%s, %s, %s)", triplet.getSubject(), triplet.getPredicate(), triplet.getObject());

            if (timeDebug) {
                System.out.println("SmartSpaceKP removeData: " + (System.currentTimeMillis() - startTime));
            }

            throw new SmartSpaceException(text + '\n' + removeResponse.Message);
        }
        if (timeDebug) {
            System.out.println("SmartSpaceKP removeData: " + (System.currentTimeMillis() - startTime));
        }
    }

    public void cleanSmartSpace() throws SmartSpaceException {
        removeData(new SmartSpaceTriplet(null, null, null));
    }

    public void leaveSmartSpace() throws SmartSpaceException {
        long startTime = System.currentTimeMillis();

        unsubscribe();

        SIBResponse leaveResponse = core.leave();
        if (leaveResponse.isConfirmed()) {
            System.out.println("Leaved!");
        } else {

            if (timeDebug) {
                System.out.println("SmartSpaceKP leaveSmartSpace: " + (System.currentTimeMillis() - startTime));
            }

            throw new SmartSpaceException(leaveResponse.Message);
        }
        if (timeDebug) {
            System.out.println("SmartSpaceKP leaveSmartSpace: " + (System.currentTimeMillis() - startTime));
        }
    }

    public void subscribeData(SmartSpaceTriplet triplet, iKPIC_subscribeHandler2 handler) throws SmartSpaceException {
        long startTime = System.currentTimeMillis();
        SIBResponse subscribeResponse = core.subscribeRDF(triplet.getSubject(), triplet.getPredicate(), triplet.getObject(), "literal", handler);

        if (subscribeResponse != null && subscribeResponse.isConfirmed()) {
            subscriptionIdList.add(subscribeResponse.subscription_id);
        } else {
            System.err.println("Some problems with subscribing");

            if (timeDebug) {
                System.out.println("SmartSpaceKP subscribeData: " + (System.currentTimeMillis() - startTime));
            }

            throw new SmartSpaceException(subscribeResponse != null ? subscribeResponse.Message : null);
        }
        if (timeDebug) {
            System.out.println("SmartSpaceKP subscribeData: " + (System.currentTimeMillis() - startTime));
        }
    }

    private void unsubscribe() throws SmartSpaceException {
        long startTime = System.currentTimeMillis();
        String exceptionMessage = "";

        System.out.println("Starting unsubscribe...");
        //sleep();

        for (String id : subscriptionIdList) {
            SIBResponse unsubscribeResponse = core.unsubscribe(id);

            // у нас проблемы с отпиской от интеллектуального пространства
            if (!unsubscribeResponse.isConfirmed()) {
                exceptionMessage += id + ": " + unsubscribeResponse.Message + '\n';
            }
        }

        subscriptionIdList.clear();

        // проблемы во время отписки были, сигнализируем это
        if (!exceptionMessage.isEmpty()) {

            if (timeDebug) {
                System.out.println("SmartSpaceKP unsubscribe: " + (System.currentTimeMillis() - startTime));
            }

            throw new SmartSpaceException(exceptionMessage);
        }

        if (timeDebug) {
            System.out.println("SmartSpaceKP unsubscribe: " + (System.currentTimeMillis() - startTime));
        }
    }

    /* test procedure */
    public void printAllData() {
        try {
            Vector<SmartSpaceTriplet> answer = query(new SmartSpaceTriplet(null, null, null));
            for (SmartSpaceTriplet it : answer) {
                System.out.println(it);
            }
        } catch (SmartSpaceException e) {
            e.printStackTrace();
        }
    }

    public void sleep() {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
